package com.codewsq.java1;

import com.codewsq.entity.Person;
import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;

public class MethodTest {

    @Test
    public void test() {
        Class<Person> clazz = Person.class;

        /*
         * getMethods()：获取运行时类及其父类的所有public修饰的方法
         * */
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        System.out.println("\n=======================================================\n");
        /*
         * getDeclaredMethods():获取当前运行时类的所有方法，不包含父类的
         * */
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
    }

    /*
    @Xxxx
    权限修饰符  返回值类型  方法名(参数类型1 形参名1,...) throws XxxException{}
     */
    @Test
    public void test1() {
        Class<Person> clazz = Person.class;

        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {

            // 1. 获取方法注解
            Annotation[] annotations = method.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println(annotation);
            }

            // 2. 获取方法权限修饰符
            int modifiers = method.getModifiers();
            String modifier = Modifier.toString(modifiers);
            System.out.print(modifier + "\t");

            // 3. 获取方法返回值类型
            Type returnType = method.getGenericReturnType();
            System.out.print(returnType + "\t");

            // 4. 获取方法名称
            String name = method.getName();
            System.out.print(name);

            System.out.print("(");
            // 5.形参列表
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes != null && parameterTypes.length > 0) {
                for (int i = 0; i < parameterTypes.length; i++) {
                    if (i == parameterTypes.length - 1) {
                        System.out.print(parameterTypes[i].getName() + " arg_" + i);
                        break;
                    }
                    System.out.print(parameterTypes[i].getName() + " arg_" + i + ",");
                }
            }
            System.out.print(")");

            // 6.方法抛出的异常
            Class<?>[] exceptionTypes = method.getExceptionTypes();
            if (exceptionTypes != null && exceptionTypes.length > 0) {
                System.out.print(" throws ");
                for (int i = 0; i < exceptionTypes.length; i++) {
                    if (i == exceptionTypes.length - 1) {
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }
                    System.out.print(exceptionTypes[i].getName() + ",");
                }
            }
            System.out.println();
            System.out.println("=======================================");
        }
    }


    /*
    如何操作运行时类中的指定的方法 -- 需要掌握
     */
    @Test
    public void test2() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class<Person> clazz = Person.class;

        // 1.实例化运行时类的对象
        Person person = clazz.newInstance();
        // 2. 指定调用运行时类的方法
        // getDeclaredMethod():参数1 ：指明获取的方法的名称  参数2：指明获取的方法的形参列表
        Method method = clazz.getDeclaredMethod("show", String.class);
        // 3.保证当前方法是可访问的
        method.setAccessible(true);
        // 4.调用方法的invoke():参数1：方法的调用者  参数2：给方法形参赋值的实参
        //   invoke()的返回值即为对应类中调用的方法的返回值。
        Object retrunValue = method.invoke(person, "中国");
        System.out.println(retrunValue);

        /*--------------------------------------调用静态方法---------------------------------------------------*/
        System.out.println("调用静态的方法");
        Method staticMethod = clazz.getDeclaredMethod("showDesc");
        staticMethod.setAccessible(true);
        //如果调用的运行时类中的方法没有返回值，则此invoke()返回null
        // 以下三种方式都可以
//        Object staticInvoke = showDesc.invoke(Person.class);
//        Object staticInvoke = staticMethod.invoke(null);
        Object staticInvoke = staticMethod.invoke(clazz);
        System.out.println(staticInvoke);
    }
}
